# -*- coding: utf-8 -*-
"""
Module Description:冷却时间不固定的倒计时方法类，使用UseTimes和ChargingTime记录
Date: 2017/2/7
Author:
"""
import datetime
from pyshare.utils.time_utils import getCT, get_another_time
from pyshare.bll.errors import ChargingError


class FloatCdChargingMixin(object):
    __slots__ = ()

    capacity = NotImplemented  # 最大上限
    remain_times = NotImplemented  # 剩余次数（不包含已冷却的时间）
    charging_time = NotImplemented  # 恢复开始时间
    cool_down_cd = NotImplemented  # 冷却CD时长

    def update(self):
        """更新数据，确保每次调用时，remain_times都是最新的"""

        add_times = int((getCT() - self.charging_time).total_seconds() // self.cool_down_cd)
        if self.remain_times >= self.capacity:
            return

        self.remain_times = min(self.remain_times + add_times, self.capacity)
        if add_times:
            self.charging_time = get_another_time(self.charging_time, seconds=add_times * self.cool_down_cd)

        # self.tb_taxation.save()

    @property
    def remaining(self):
        """剩余次数"""
        self.update()
        return self.remain_times

    @remaining.setter
    def remaining(self, value):
        """修改剩余次数"""
        if value < 0:
            raise ChargingError('out of capacity')
        self.update()

        if not (value <= self.remaining and self.ischarging()):
            self.charging_time = getCT()

        self.remain_times = value

    def isfull(self):
        """可用次数是否已满。

        :rtype: bool
        """
        return self.remaining >= self.capacity

    def ischarging(self):
        """是否正在补充。

        :rtype: bool
        """
        return not self.isfull()

    def isempty(self):
        """可用次数是否为 0 。

        :rtype: bool
        """
        return self.remaining == 0

    def charged_period(self):
        """当前补充已进行的时间。

        :rtype: datetime.timedelta
        """
        if not self.ischarging():
            raise ChargingError('not charging')
        t = (getCT() - self.charging_time).total_seconds() % self.cool_down_cd
        return datetime.timedelta(seconds=t)

    def waiting_period(self):
        """距当前补充完成仍需等待的时间。

        :rtype: datetime.timedelta
        """
        if not self.ischarging():
            raise ChargingError('not charging')

        return datetime.timedelta(seconds=self.cool_down_cd) - self.charged_period()

    def charge_at(self):
        """当前补充完成的时刻。

        :rtype: datetime.datetime
        """
        return getCT() + self.waiting_period()

    def asdict(self):
        d = {
            'Remaining': self.remaining,
            'MaxRounds': self.capacity,
        }

        if self.ischarging():
            try:
                d['CoolDown'] = self.waiting_period().total_seconds()
                d['ChargeAt'] = self.charge_at()
            except ChargingError:
                pass

        return d
